<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!-- 网页信息 -->
    <link rel="icon" href="/favicon.ico" type="image/x-icon" />
    <title>工具——图片转换与压缩</title>
    <meta name="author" content="尘跃" />
    <meta name="description" content="工具——图片转换与压缩" />

    <!-- Facebook Open Graph -->
    <meta property="og:site_name" content="" />
    <meta property="og:title" content="工具——图片转换与压缩" />
    <meta property="og:type" content="website" />
    <meta
        property="og:url"
        content="http://cyue.net/pages/tool/image.html"
    />
    <meta property="og:image" content="http://cyue.net/favicon.png" />
    <meta
        property="工具——图片转换与压缩"
    />

    <!-- Twitter Cards -->
    <meta name="twitter:card" content="summary" />
    <meta name="twitter:image" content="http://cyue.net/favicon.png" />
    <meta name="twitter:title" content="工具——图片转换与压缩" />
    <meta
        name="twitter:description"
        content="工具——图片转换与压缩"
    />
    <meta name="twitter:creator" content="@尘跃" />
    <meta name="twitter:site" content="@cyue.net" />

    <!-- style -->
    <link rel="stylesheet/less" type="text/css" href="/css/style.less">
    <!-- less -->
    <script src="/js/third/less.min.js"></script>

    <!-- Vue3 -->
    <script src="/js/vue/vue.global.prod.js"></script>
    <!-- website configuration -->
    <script src="/js/configuration.js"></script>
    <!-- 百度统计 -->
    <script src="/js/tongji.js"></script>

    <style>
        #app {
            display: flex;
            flex-direction: column;
            box-sizing: border-box;
            padding: 2em;
        }

        .container {
            width: 100%;
            display: grid;
            grid-template-columns: 1fr;
            align-items: center;
        }

        @media (min-width: 40rem) {
            #app {
                padding: 2rem 4rem;
            }

            .container {
                align-items: start;
                grid-template-columns: 1fr 1fr;
            }
        }

        h1 {
            margin-bottom: 0.5em;
        }

        label {
            margin-top: 0.25em;
            margin-right: 0.25em;
        }

        input,
        textarea {
            box-sizing: border-box;
            padding: 0.5em;
            margin-top: 0.25em;
        }

        textarea {
            transition: all 50ms;
            width: 16rem;
            height: 10rem;
        }

        /*  */
        #form {
            display: flex;
            flex-direction: column;
            gap: 0.5em;
            margin-top: 0.5em;
        }

        main img {
            margin: 1em;
            width: 80%;
        }

        form .button {
            background-color: transparent;
            min-width: 5em;
            width: fit-content;
            margin: 0.5em 1em;
        }

    </style>
</head>
<body>
    <page-header></page-header>

    <div class="block-spacer"></div>

    <main id="app">
        <h1>图片转换与压缩</h1>
        <div class="container">
            <div>
                <h2>输入</h2>
                <form id="form" @submit="onSubmit">
                    <div>
                        <label for="input-range">品质（仅支持JPG与WebP图片）</label>
                        <br />
                        <div style="display: flex;align-items: center;gap: 0.25em">
                            <input id="input-range" type="range" v-model="quality" />
                            <span>{{ quality }}</span>
                        </div>
                    </div>
                    <div>
                        <label for="select-mime">输出格式</label>
                        <select id="select-mime" name="mimeType" v-model="mimeType">
                            <option value="auto">原格式</option>
                            <option value="image/png">png</option>
                            <option value="image/jpeg">jpeg</option>
                            <option value="image/webp">webp</option>
                        </select>
                    </div>
                    <div>
                        <label for="input-img">图片</label>
                        <input id="input-img" type="file" accept="image/*"
                            v-on:change="inputIMGFile = $event.target.files[0] || inputIMGFile">
                        <br />
                        <img v-if="inputIMGURL" :src="inputIMGURL" alt="输入图片">
                        <div v-if="inputIMGFile">
                            <div>
                                名称：
                                <span>{{ inputIMGFile.name }}</span>
                            </div>
                            <div>
                                大小：
                                <span>{{ (inputIMGFile.size / 1024 / 1024).toFixed(3) }}MB</span>
                            </div>
                        </div>
                    </div>
                    <div class="flex" v-if="inputIMGFile">
                        <input class="button" type="submit" value="转换并压缩">
                        <a class="button" :href="outputIMGURL" :download="outputIMGFile ? outputIMGFile.name : ''">
                            保存到本地
                        </a>
                    </div>
                    <span v-if="outputIMGFile">
                        转换与压缩花费了 {{ spendTime }} 毫秒
                    </span>
                </form>
            </div>

            <div>
                <h2>输出</h2>
                <div>
                    <img v-if="outputIMGURL" :src="outputIMGURL" alt="输出图片">
                    <div v-if="outputIMGFile">
                        <div>
                            名称：
                            <span>{{ outputIMGFile.name }}</span>
                        </div>
                        <div>
                            大小：
                            <span>{{ (outputIMGFile.size / 1024 / 1024).toFixed(3) }}MB</span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </main>
    <page-footer></page-footer>

    <!-- web component -->
    <script src="/js/component.js"></script>
    <!-- style -->
    <script src="/js/style.js"></script>
    <!-- compressor -->
    <script src="/js/third/compressor.min.js"></script>
    <!--  -->
    <script>
        const { createApp } = Vue;
        createApp({
            mounted() {},
            data() {
                return {
                    quality: 100,
                    mimeType: "auto",
                    inputIMGFile: undefined,
                    inputIMGURL: "/images/image.default.png",
                    outputIMGFile: undefined,
                    outputIMGURL: undefined,
                    spendTime: 0,
                }
            },

            watch: {
                async inputIMGFile(newV, oldV) {
                    if (!newV) {
                        this.inputIMGFile = oldV;
                        return;
                    }
                    this.inputIMGURL = await this.createIMGURL(newV);
                },
                inputIMGURL(_newV, oldV) {
                    this.revokeIMGURL(oldV);
                },
                async outputIMGFile(newV, oldV) {
                    if (!newV) {
                        this.outputIMGURL = oldV;
                        return;
                    }
                    this.outputIMGURL = await this.createIMGURL(newV);
                },
                outputIMGURL(_newV, oldV) {
                    this.revokeIMGURL(oldV);
                },
            },

            methods: {
                onSubmit(e) {
                    e.preventDefault();
                    this.compressImage(this.inputIMGFile);
                },

                createIMGURL(file) {
                    return new Promise((resolve, reject) => {
                        if (
                            window.URL &&
                            typeof window.URL.createObjectURL === "function"
                        ) {
                            resolve(window.URL.createObjectURL(file));
                            return;
                        }
                        const reader = new FileReader();
                        reader.onload = (e) => {
                            resolve(
                                `data:${this.mimeType === "auto" ? "image/png" : this.mimeType};base64,`
                                + e.target.result
                            );
                        };
                        reader.onerror = reject;
                        reader.readAsDataURL(file);
                    });
                },
                revokeIMGURL(url) {
                    if (!url || url.startsWith("data:image")) {
                        return;
                    }
                    try {
                        window.URL.revokeObjectURL(url);
                    } catch (e) {
                        console.error(e);
                    }
                },

                async compressImage(imgFile) {
                    if (!imgFile) {
                        console.log("file is empty");
                    }

                    const startTime = Date.now();
                    const compressor = new Compressor(imgFile, {
                        quality: this.quality / 100,
                        mimeType: this.mimeType,
                        success: (blob) => {
                            this.outputIMGFile = blob;
                            this.spendTime = Date.now() - startTime;
                        },
                        error: (err) => {}
                    });
                },
            }
        }).mount("#app");

    </script>
</body>
</html>


